package com.hy.example.shared.feign;



import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.hy.example.shared.exception.BusinessException;
import com.hy.example.common.api.result.ApiResult;
import feign.FeignException;
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.TimeZone;

@Slf4j
public class FeignDecoder implements Decoder {

    private final Decoder decoder;

    public static final ObjectMapper objectMapper = new ObjectMapper();

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    static {
        //取消时间的转化格式，默认是时间戳,同时需要设置要表现的时间格式
        objectMapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
        objectMapper.registerModule(javaTimeModule);
        objectMapper.registerModule(new ParameterNamesModule(JsonCreator.Mode.DEFAULT));
        // 设置时区
        objectMapper.setTimeZone(TimeZone.getDefault());
    }

    public FeignDecoder(Decoder decoder) {
        this.decoder = decoder;
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        //注意，feign的相关接口返回值不要有code字段，如果有，请用ApiResult包起来
        if (type instanceof ParameterizedType pType) {
            Type rawType = pType.getRawType();
            if (rawType instanceof Class && ApiResult.class.isAssignableFrom((Class<?>) rawType)) {
                return decoder.decode(response, type);
            }
        }
        String resultStr = this.getResponseJson(response);
        processException(resultStr);
        return decoder.decode(response.toBuilder().body(resultStr, StandardCharsets.UTF_8).build(), type);
    }

    private void processException(String json) {
        log.debug("result is : {}", json);
        if (!StringUtils.hasLength(json)) {
            return;
        }
        try {
            ApiResult<?> result = objectMapper.readValue(json, new TypeReference<>() {
            });
            if (Objects.isNull(result.getMsg()) && Objects.isNull(result.getContent())&& result.getCode() == 0) {
                return;
            }
            if (result.isSuccess()) {
                return;
            }
            throw new BusinessException(result.getMsg());
        } catch (JsonProcessingException e) {
            log.debug(e.getMessage());
        }

    }

    private String getResponseJson(Response response) throws IOException {
        if (response == null || response.body() == null) {
            return null;
        }
        try (InputStream inputStream = response.body().asInputStream()) {
            return StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        }
    }
}
